package serv_cmd

import (
	"context"
	"fmt"
	"sort"
	"strings"

	"atomgit.com/openlinksaas/proto-gen-go.git/swarm_proxy_api"
	"atomgit.com/openlinksaas/swarm_api_proxy/config"
	"atomgit.com/openlinksaas/swarm_api_proxy/utils"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/swarm"
)

func (apiImpl *SwarmProxyApiImpl) ListNameSpace(ctx context.Context, req *swarm_proxy_api.ListNameSpaceRequest) (*swarm_proxy_api.ListNameSpaceResponse, error) {
	emptyList := []string{}

	//检查权限
	tokenInfo, err := apiImpl.getTokenInfo(apiImpl.cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &swarm_proxy_api.ListNameSpaceResponse{
			Code:          swarm_proxy_api.ListNameSpaceResponse_CODE_WRONG_TOKEN,
			ErrMsg:        "错误的访问令牌",
			NameSpaceList: emptyList,
		}, nil
	}
	c, err := utils.GetDockerClient(apiImpl.cfg.ServerUrl, apiImpl.cfg.CertPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	exist, err := apiImpl.existProject(ctx, c, tokenInfo.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &swarm_proxy_api.ListNameSpaceResponse{
			Code:          swarm_proxy_api.ListNameSpaceResponse_CODE_NO_PERMISSION,
			ErrMsg:        "没有权限",
			NameSpaceList: emptyList,
		}, nil
	}

	filter := filters.NewArgs()
	filter.Add("label", config.LABEL_NAMESPACE)
	svcItemList, err := c.ServiceList(ctx, types.ServiceListOptions{
		Filters: filter,
	})
	if err != nil {
		return nil, err
	}

	tmpMap := map[string]bool{}
	for _, servItem := range svcItemList {
		name, ok := servItem.Spec.Labels[config.LABEL_NAMESPACE]
		if ok {
			tmpMap[name] = true
		}
	}

	nameList := []string{}
	for k, _ := range tmpMap {
		nameList = append(nameList, k)
	}
	sort.Strings(nameList)
	return &swarm_proxy_api.ListNameSpaceResponse{
		Code:          swarm_proxy_api.ListNameSpaceResponse_CODE_OK,
		NameSpaceList: nameList,
	}, nil
}

func (apiImpl *SwarmProxyApiImpl) ListService(ctx context.Context, req *swarm_proxy_api.ListServiceRequest) (*swarm_proxy_api.ListServiceResponse, error) {
	emptyList := []*swarm_proxy_api.ServiceInfo{}

	//检查权限
	tokenInfo, err := apiImpl.getTokenInfo(apiImpl.cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &swarm_proxy_api.ListServiceResponse{
			Code:        swarm_proxy_api.ListServiceResponse_CODE_WRONG_TOKEN,
			ErrMsg:      "错误的访问令牌",
			ServiceList: emptyList,
		}, nil
	}
	c, err := utils.GetDockerClient(apiImpl.cfg.ServerUrl, apiImpl.cfg.CertPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	exist, err := apiImpl.existProject(ctx, c, tokenInfo.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &swarm_proxy_api.ListServiceResponse{
			Code:        swarm_proxy_api.ListServiceResponse_CODE_NO_PERMISSION,
			ErrMsg:      "没有权限",
			ServiceList: emptyList,
		}, nil
	}

	filter := filters.NewArgs()
	filter.Add("label", config.LABEL_NAMESPACE+"="+req.NameSpace)
	svcItemList, err := c.ServiceList(ctx, types.ServiceListOptions{
		Filters: filter,
		Status:  true,
	})
	if err != nil {
		return nil, err
	}

	svcList := []*swarm_proxy_api.ServiceInfo{}
	for _, svcItem := range svcItemList {
		name := svcItem.Spec.Labels[config.LABEL_NAMESPACE]
		if name != req.NameSpace {
			continue
		}
		labels := []*swarm_proxy_api.Label{}
		for k, v := range svcItem.Spec.Labels {
			labels = append(labels, &swarm_proxy_api.Label{
				Key:   k,
				Value: v,
			})
		}

		image := svcItem.Spec.TaskTemplate.ContainerSpec.Image
		pos := strings.Index(image, "@")
		if pos != -1 {
			image = image[:pos]
		}
		svcList = append(svcList, &swarm_proxy_api.ServiceInfo{
			ServiceId:    svcItem.ID,
			Name:         svcItem.Spec.Name,
			LabelList:    labels,
			Image:        image,
			CreateTime:   svcItem.CreatedAt.UnixNano() / 1e6,
			UpdateTime:   svcItem.UpdatedAt.UnixNano() / 1e6,
			RunningTasks: uint32(svcItem.ServiceStatus.RunningTasks),
			DesiredTasks: uint32(svcItem.ServiceStatus.DesiredTasks),
		})
	}

	return &swarm_proxy_api.ListServiceResponse{
		Code:        swarm_proxy_api.ListServiceResponse_CODE_OK,
		ServiceList: svcList,
	}, nil
}

func (apiImpl *SwarmProxyApiImpl) ListTask(ctx context.Context, req *swarm_proxy_api.ListTaskRequest) (*swarm_proxy_api.ListTaskResponse, error) {
	emptyList := []*swarm_proxy_api.TaskInfo{}

	//检查权限
	tokenInfo, err := apiImpl.getTokenInfo(apiImpl.cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &swarm_proxy_api.ListTaskResponse{
			Code:     swarm_proxy_api.ListTaskResponse_CODE_WRONG_TOKEN,
			ErrMsg:   "错误的访问令牌",
			TaskList: emptyList,
		}, nil
	}
	c, err := utils.GetDockerClient(apiImpl.cfg.ServerUrl, apiImpl.cfg.CertPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	exist, err := apiImpl.existProject(ctx, c, tokenInfo.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &swarm_proxy_api.ListTaskResponse{
			Code:     swarm_proxy_api.ListTaskResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			TaskList: emptyList,
		}, nil
	}

	nodeItemList, err := c.NodeList(ctx, types.NodeListOptions{})
	if err != nil {
		return nil, err
	}
	nodeMap := map[string]string{}
	for _, nodeItem := range nodeItemList {
		nodeMap[nodeItem.ID] = nodeItem.Description.Hostname
	}

	filter := filters.NewArgs()
	taskItemList, err := c.TaskList(ctx, types.TaskListOptions{
		Filters: filter,
	})
	if err != nil {
		return nil, err
	}

	servIdMap := map[string]bool{}
	for _, servId := range req.ServiceIdList {
		servIdMap[servId] = true
	}

	taskList := []*swarm_proxy_api.TaskInfo{}
	for _, taskItem := range taskItemList {
		if !servIdMap[taskItem.ServiceID] {
			continue
		}
		if taskItem.Status.State == swarm.TaskStateComplete || taskItem.Status.State == swarm.TaskStateShutdown {
			continue
		}
		labels := []*swarm_proxy_api.Label{}
		for k, v := range taskItem.Labels {
			labels = append(labels, &swarm_proxy_api.Label{
				Key:   k,
				Value: v,
			})
		}
		containerId := ""
		if taskItem.Status.ContainerStatus != nil {
			containerId = taskItem.Status.ContainerStatus.ContainerID
		}
		portList := []*swarm_proxy_api.PortInfo{}
		for _, portItem := range taskItem.Status.PortStatus.Ports {
			portList = append(portList, &swarm_proxy_api.PortInfo{
				Name:        portItem.Name,
				Protocol:    string(portItem.Protocol),
				TargetPort:  portItem.TargetPort,
				PublishPort: portItem.PublishedPort,
				PublishMode: string(portItem.PublishMode),
			})
		}
		taskList = append(taskList, &swarm_proxy_api.TaskInfo{
			TaskId:      taskItem.ID,
			Name:        fmt.Sprint(taskItem.Slot),
			LabelList:   labels,
			ServiceId:   taskItem.ServiceID,
			NodeName:    nodeMap[taskItem.NodeID],
			Status:      string(taskItem.Status.State),
			ContainerId: containerId,
			PortList:    portList,
			CreateTime:  taskItem.CreatedAt.UnixNano() / 1e6,
			UpdateTime:  taskItem.UpdatedAt.UnixNano() / 1e6,
		})
	}
	return &swarm_proxy_api.ListTaskResponse{
		Code:     swarm_proxy_api.ListTaskResponse_CODE_OK,
		TaskList: taskList,
	}, nil
}

func (apiImpl *SwarmProxyApiImpl) UpdateImage(ctx context.Context, req *swarm_proxy_api.UpdateImageRequest) (*swarm_proxy_api.UpdateImageResponse, error) {
	//检查权限
	tokenInfo, err := apiImpl.getTokenInfo(apiImpl.cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &swarm_proxy_api.UpdateImageResponse{
			Code:   swarm_proxy_api.UpdateImageResponse_CODE_WRONG_TOKEN,
			ErrMsg: "错误的访问令牌",
		}, nil
	}
	c, err := utils.GetDockerClient(apiImpl.cfg.ServerUrl, apiImpl.cfg.CertPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	exist, err := apiImpl.existProject(ctx, c, tokenInfo.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &swarm_proxy_api.UpdateImageResponse{
			Code:   swarm_proxy_api.UpdateImageResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !tokenInfo.Admin {
		userPerm := apiImpl.getUserPerm(ctx, tokenInfo.ProjectId, tokenInfo.MemberUserId)
		if !userPerm.UpdateImage {
			return &swarm_proxy_api.UpdateImageResponse{
				Code:   swarm_proxy_api.UpdateImageResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
	}

	svcItem, _, err := c.ServiceInspectWithRaw(ctx, req.ServiceId, types.ServiceInspectOptions{})
	if err != nil {
		return &swarm_proxy_api.UpdateImageResponse{
			Code:   swarm_proxy_api.UpdateImageResponse_CODE_NO_PERMISSION,
			ErrMsg: "对象不存在",
		}, nil
	}

	svcItem.Spec.TaskTemplate.ContainerSpec.Image = req.Image
	_, err = c.ServiceUpdate(ctx, req.ServiceId, svcItem.Version, svcItem.Spec, types.ServiceUpdateOptions{})
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return &swarm_proxy_api.UpdateImageResponse{
		Code: swarm_proxy_api.UpdateImageResponse_CODE_OK,
	}, nil
}

func (apiImpl *SwarmProxyApiImpl) UpdateScale(ctx context.Context, req *swarm_proxy_api.UpdateScaleRequest) (*swarm_proxy_api.UpdateScaleResponse, error) {
	//检查权限
	tokenInfo, err := apiImpl.getTokenInfo(apiImpl.cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &swarm_proxy_api.UpdateScaleResponse{
			Code:   swarm_proxy_api.UpdateScaleResponse_CODE_WRONG_TOKEN,
			ErrMsg: "错误的访问令牌",
		}, nil
	}
	c, err := utils.GetDockerClient(apiImpl.cfg.ServerUrl, apiImpl.cfg.CertPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	exist, err := apiImpl.existProject(ctx, c, tokenInfo.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &swarm_proxy_api.UpdateScaleResponse{
			Code:   swarm_proxy_api.UpdateScaleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !tokenInfo.Admin {
		userPerm := apiImpl.getUserPerm(ctx, tokenInfo.ProjectId, tokenInfo.MemberUserId)
		if !userPerm.UpdateScale {
			return &swarm_proxy_api.UpdateScaleResponse{
				Code:   swarm_proxy_api.UpdateScaleResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
	}

	svcItem, _, err := c.ServiceInspectWithRaw(ctx, req.ServiceId, types.ServiceInspectOptions{})
	if err != nil {
		return &swarm_proxy_api.UpdateScaleResponse{
			Code:   swarm_proxy_api.UpdateScaleResponse_CODE_NO_PERMISSION,
			ErrMsg: "对象不存在",
		}, nil
	}
	if svcItem.Spec.Mode.Replicated == nil {
		return &swarm_proxy_api.UpdateScaleResponse{
			Code:   swarm_proxy_api.UpdateScaleResponse_CODE_NO_PERMISSION,
			ErrMsg: "对象模式不匹配",
		}, nil
	}
	scale := uint64(req.Scale)
	svcItem.Spec.Mode.Replicated.Replicas = &scale
	_, err = c.ServiceUpdate(ctx, req.ServiceId, svcItem.Version, svcItem.Spec, types.ServiceUpdateOptions{})
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return &swarm_proxy_api.UpdateScaleResponse{
		Code: swarm_proxy_api.UpdateScaleResponse_CODE_OK,
	}, nil
}
